﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.DependencyInjection;

namespace StyleMVVM.Validation.Impl
{
	public sealed class DefaultValidationContextProvider : IValidationContextProvider
	{
		private class ContextHolder
		{
			public WeakReference ValidationObject { get; set; }

			public IValidationContext Context { get; set; }
		}

		private readonly object contextLockObject = new object();

		private readonly Dictionary<int, List<ContextHolder>> validationContexts =
			new Dictionary<int, List<ContextHolder>>();

		public static void RegisterExport(IDependencyInjectionContainer container)
		{
			container.Register(typeof(DefaultValidationContextProvider))
			         .As(typeof(IValidationContextProvider))
			         .AndShared();
		}

		public IValidationContext ProvideContext(object validationObject,
		                                         bool monitor,
		                                         bool shared,
		                                         CreateNewContextDelegate createDelegate)
		{
			IValidationContext returnValue = null;
			int hash = validationObject.GetHashCode();
			List<ContextHolder> holders;

			if (shared)
			{
				lock (contextLockObject)
				{
					if (validationContexts.TryGetValue(hash, out holders))
					{
						for (int i = 0; i < holders.Count;)
						{
							ContextHolder holder = holders[i];

							if (holder.ValidationObject.Target == validationObject)
							{
								returnValue = holder.Context;
								break;
							}

							if (!holder.ValidationObject.IsAlive)
							{
								holders.RemoveAt(i);
							}
							else
							{
								i++;
							}
						}
					}

					if (returnValue == null)
					{
						returnValue = createDelegate(validationObject, monitor, true);

						ContextHolder contextHolder = new ContextHolder
							                              {
								                              Context = returnValue,
								                              ValidationObject = new WeakReference(validationObject)
							                              };
						if (holders == null)
						{
							holders = new List<ContextHolder>();

							validationContexts.Add(hash, holders);
						}

						holders.Add(contextHolder);
					}
				}
			}
			else
			{
				returnValue = createDelegate(validationObject, monitor, false);
			}

			return returnValue;
		}
	}
}